///////////////////////////////////////////////////////////////////////////////
//
// wxFormBuilder - A Visual Dialog Editor for wxWidgets.
// Copyright (C) 2005 José Antonio Hurtado
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Written by
//   José Antonio Hurtado - joseantonio.hurtado@gmail.com
//   Juan Antonio Ortega  - jortegalalmolda@gmail.com
//
///////////////////////////////////////////////////////////////////////////////

#include <wx/calctrl.h>
#include <wx/clrpicker.h>
#include <wx/dataview.h>
#include <wx/datectrl.h>
#include <wx/dirctrl.h>
#include <wx/filepicker.h>
#include <wx/fontpicker.h>
#include <wx/grid.h>
#include <wx/html/htmlwin.h>
#include <wx/hyperlink.h>
#include <wx/propgrid/manager.h>
#include <wx/ribbon/buttonbar.h>
#include <wx/ribbon/gallery.h>
#include <wx/ribbon/toolbar.h>
#include <wx/richtext/richtextctrl.h>
#include <wx/spinctrl.h>
#include <wx/srchctrl.h>
#include <wx/stc/stc.h>
#include <wx/tglbtn.h>
#include <wx/timectrl.h>
#include <wx/treelist.h>
#include <wx/vlbox.h>
#include <wx/xrc/xmlres.h>

#include <common/xmlutils.h>
#include <plugin_interface/plugin.h>
#include <plugin_interface/xrcconv.h>

#include "logo.xpm"
#include "smiley.xpm"

#ifdef USE_MEDIACTRL
    #include <wx/mediactrl.h>
#endif


/**
Event handler for events generated by controls in this plugin
*/
class ComponentEvtHandler : public wxEvtHandler
{
private:
    wxWindow* m_window;
    IManager* m_manager;

public:
    ComponentEvtHandler(wxWindow* win, IManager* manager) : m_window(win), m_manager(manager) {}

protected:
    void OnGridClick([[maybe_unused]] wxGridEvent& event)
    {
        m_manager->SelectObject(m_window);
        event.Skip();
    }

    void OnGridColSize([[maybe_unused]] wxGridSizeEvent& event)
    {
        wxGrid* grid = wxDynamicCast(m_window, wxGrid);
        if (NULL == grid) {
            return;
        }

        wxString sizes;
        for (int i = 0; i < grid->GetNumberCols(); ++i) { sizes += wxString::Format(wxT("%i,"), grid->GetColSize(i)); }
        sizes = sizes.substr(0, sizes.length() - 1);

        m_manager->ModifyProperty(m_window, _("column_sizes"), sizes, true);
    }

    void OnGridRowSize([[maybe_unused]] wxGridSizeEvent& event)
    {
        wxGrid* grid = wxDynamicCast(m_window, wxGrid);
        if (NULL == grid) {
            return;
        }

        wxString sizes;
        for (int i = 0; i < grid->GetNumberRows(); ++i) { sizes += wxString::Format(wxT("%i,"), grid->GetRowSize(i)); }
        sizes = sizes.substr(0, sizes.length() - 1);

        m_manager->ModifyProperty(m_window, _("row_sizes"), sizes, true);
    }

    void OnColourPickerColourChanged([[maybe_unused]] wxColourPickerEvent& event)
    {
        wxColourPickerCtrl* window = wxDynamicCast(m_window, wxColourPickerCtrl);
        if (window != NULL) {
            wxColour colour = window->GetColour();
            m_manager->ModifyProperty(
            window, _("colour"), wxString::Format(wxT("%d,%d,%d"), colour.Red(), colour.Green(), colour.Blue()));
        }
    }

    void OnFontPickerFontChanged([[maybe_unused]] wxFontPickerEvent& event)
    {
        wxFontPickerCtrl* window = wxDynamicCast(m_window, wxFontPickerCtrl);
        if (window != NULL) {
            wxFont font = window->GetSelectedFont();
            m_manager->ModifyProperty(
            window, _("value"),
            wxString::Format(
                wxT("%s,%d,%d,%d"), font.GetFaceName().c_str(), font.GetStyle(), font.GetWeight(), font.GetPointSize()));
        }
    }

    void OnFilePickerFileChanged([[maybe_unused]] wxFileDirPickerEvent& event)
    {
        wxFilePickerCtrl* window = wxDynamicCast(m_window, wxFilePickerCtrl);
        if (window != NULL) {
            m_manager->ModifyProperty(window, _("value"), window->GetPath());
        }
    }

    void OnDirPickerDirChanged([[maybe_unused]] wxFileDirPickerEvent& event)
    {
        wxDirPickerCtrl* window = wxDynamicCast(m_window, wxDirPickerCtrl);
        if (window != NULL) {
            m_manager->ModifyProperty(window, _("value"), window->GetPath());
        }
    }

    void OnText([[maybe_unused]] wxCommandEvent& event)
    {
        wxSearchCtrl* sc = wxDynamicCast(m_window, wxSearchCtrl);
        if (sc != NULL) {
            m_manager->ModifyProperty(m_window, _("value"), sc->GetValue());
            sc->SetInsertionPointEnd();
            sc->SetFocus();
        }

        event.Skip();
    }

    // Enable folding for wxStyledTextCtrl
    void OnMarginClick([[maybe_unused]] wxStyledTextEvent& event)
    {
        wxStyledTextCtrl* scintilla = wxDynamicCast(m_window, wxStyledTextCtrl);
        if (scintilla != NULL) {
            if (event.GetMargin() == 1) {
                int lineClick = scintilla->LineFromPosition(event.GetPosition());
                int levelClick = scintilla->GetFoldLevel(lineClick);
                if ((levelClick & wxSTC_FOLDLEVELHEADERFLAG) > 0) {
                    scintilla->ToggleFold(lineClick);
                }
            }
        }
        event.Skip();
    }

    void OnRibbonBarPageChanged([[maybe_unused]] wxRibbonBarEvent& event)
    {
        if (m_window != event.GetEventObject()) {
            return;
        }

        wxRibbonBar* rb = wxDynamicCast(event.GetEventObject(), wxRibbonBar);
        if (rb == NULL) {
            return;
        }

        int selPage = rb->GetActivePage();

        size_t count = m_manager->GetChildCount(m_window);
        for (size_t i = 0; i < count; i++) {
            wxObject* wxChild = m_manager->GetChild(m_window, i);
            IObject* iChild = m_manager->GetIObject(wxChild);
            if (iChild) {
                if (int(i) == selPage && iChild->GetPropertyAsInteger(_("select")) == 0) {
                    m_manager->ModifyProperty(wxChild, _("select"), wxT("1"), false);
                } else if (int(i) != selPage && iChild->GetPropertyAsInteger(_("select")) != 0) {
                    m_manager->ModifyProperty(wxChild, _("select"), wxT("0"), false);
                }
            }
        }

        // Select the corresponding ribbon page in the object tree
        if (NULL != rb) {
            m_manager->SelectObject(rb->GetPage(selPage));
        }
    }

    wxDECLARE_EVENT_TABLE();
};

wxBEGIN_EVENT_TABLE(ComponentEvtHandler, wxEvtHandler)
EVT_COLOURPICKER_CHANGED(wxID_ANY, ComponentEvtHandler::OnColourPickerColourChanged)
EVT_FONTPICKER_CHANGED(wxID_ANY, ComponentEvtHandler::OnFontPickerFontChanged)
EVT_FILEPICKER_CHANGED(wxID_ANY, ComponentEvtHandler::OnFilePickerFileChanged)
EVT_DIRPICKER_CHANGED(wxID_ANY, ComponentEvtHandler::OnDirPickerDirChanged)
EVT_TEXT(wxID_ANY, ComponentEvtHandler::OnText)

// Grid also seems to ignore clicks
EVT_GRID_CELL_LEFT_CLICK(ComponentEvtHandler::OnGridClick)
EVT_GRID_LABEL_LEFT_CLICK(ComponentEvtHandler::OnGridClick)

EVT_GRID_COL_SIZE(ComponentEvtHandler::OnGridColSize)
EVT_GRID_ROW_SIZE(ComponentEvtHandler::OnGridRowSize)

EVT_STC_MARGINCLICK(wxID_ANY, ComponentEvtHandler::OnMarginClick)
EVT_RIBBONBAR_PAGE_CHANGED(wxID_ANY, ComponentEvtHandler::OnRibbonBarPageChanged)
wxEND_EVENT_TABLE()

/**
Event handler for events generated by wxGenericDirCtrl.
*/
class GenericDirCtrlEvtHandler : public wxEvtHandler
{
public:
    GenericDirCtrlEvtHandler(wxWindow* win, IManager* manager) : m_window(win), m_manager(manager) {}

protected:
    void OnGenericDirCtrlLeftClick([[maybe_unused]] wxMouseEvent& event)
    {
        m_manager->SelectObject(m_window);
        event.Skip();
    }

    wxDECLARE_EVENT_TABLE();

private:
    wxWindow* m_window;
    IManager* m_manager;
};

wxBEGIN_EVENT_TABLE(GenericDirCtrlEvtHandler, wxEvtHandler)
// GenericDirCtrl also seems to ignore clicks
EVT_LEFT_DOWN(GenericDirCtrlEvtHandler::OnGenericDirCtrlLeftClick)
wxEND_EVENT_TABLE()

///////////////////////////////////////////////////////////////////////////////

class CalendarCtrlComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        return new wxCalendarCtrl(
          (wxWindow*)parent, wxID_ANY, wxDefaultDateTime, obj->GetPropertyAsPoint(_("pos")),
          obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        return xfb;
    }
};

class DatePickerCtrlComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        return new wxDatePickerCtrl(
          (wxWindow*)parent, wxID_ANY, wxDefaultDateTime, obj->GetPropertyAsPoint(_("pos")),
          obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        return xfb;
    }
};

class TimePickerCtrlComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        return new wxTimePickerCtrl(
          (wxWindow*)parent, wxID_ANY, wxDefaultDateTime, obj->GetPropertyAsPoint(_("pos")),
          obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        return xfb;
    }
};

class RichTextCtrlComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {

        wxString text = obj->GetPropertyAsString(_("value"));

        wxRichTextCtrl* richText = new wxRichTextCtrl(
          (wxWindow*)parent, wxID_ANY, text, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        if (!text.empty()) {
            return richText;
        }

        wxFont textFont = wxFont(12, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
        wxFont boldFont = wxFont(12, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
        wxFont italicFont = wxFont(12, wxFONTFAMILY_ROMAN, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_NORMAL);

        wxFont font(12, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);

        wxRichTextCtrl& r = *richText;
        r.Freeze();
        r.SetDefaultStyle(wxRichTextAttr());
        r.SetFont(font);
        r.BeginSuppressUndo();

        r.BeginParagraphSpacing(0, 20);

        r.BeginAlignment(wxTEXT_ALIGNMENT_CENTRE);
        r.BeginBold();

        r.BeginFontSize(14);
        r.WriteText(
          wxT("Welcome to wxRichTextCtrl, a wxWidgets control for editing and presenting styled text and images"));
        r.EndFontSize();
        r.Newline();

        r.BeginItalic();
        r.WriteText(wxT("by Julian Smart"));
        r.EndItalic();

        r.EndBold();

        r.Newline();
        r.WriteImage(wxBitmap(logo_xpm));

        r.EndAlignment();

        r.Newline();

        r.WriteText(wxT("What can you do with this thing? "));
        r.WriteImage(wxBitmap(smiley_xpm));
        r.WriteText(wxT(" Well, you can change text "));

        r.BeginTextColour(wxColour(255, 0, 0));
        r.WriteText(wxT("colour, like this red bit."));
        r.EndTextColour();

        r.BeginTextColour(wxColour(0, 0, 255));
        r.WriteText(wxT(" And this blue bit."));
        r.EndTextColour();

        r.WriteText(wxT(" Naturally you can make things "));
        r.BeginBold();
        r.WriteText(wxT("bold "));
        r.EndBold();
        r.BeginItalic();
        r.WriteText(wxT("or italic "));
        r.EndItalic();
        r.BeginUnderline();
        r.WriteText(wxT("or underlined."));
        r.EndUnderline();

        r.BeginFontSize(14);
        r.WriteText(wxT(" Different font sizes on the same line is allowed, too."));
        r.EndFontSize();

        r.WriteText(wxT(" Next we'll show an indented paragraph."));

        r.BeginLeftIndent(60);
        r.Newline();

        r.WriteText(wxT("Indented paragraph."));
        r.EndLeftIndent();

        r.Newline();

        r.WriteText(wxT("Next, we'll show a first-line indent, achieved using BeginLeftIndent(100, -40)."));

        r.BeginLeftIndent(100, -40);
        r.Newline();

        r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter."));
        r.EndLeftIndent();

        r.Newline();

        r.WriteText(wxT("Numbered bullets are possible, again using subindents:"));

        r.BeginNumberedBullet(1, 100, 60);
        r.Newline();

        r.WriteText(
          wxT("This is my first item. Note that wxRichTextCtrl doesn't automatically do numbering, but this will be "
              "added later."));
        r.EndNumberedBullet();

        r.BeginNumberedBullet(2, 100, 60);
        r.Newline();

        r.WriteText(wxT("This is my second item."));
        r.EndNumberedBullet();

        r.Newline();

        r.WriteText(wxT("The following paragraph is right-indented:"));

        r.BeginRightIndent(200);
        r.Newline();

        r.WriteText(
          wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into "
              "the cafe, which is nothing remarkable."));
        r.EndRightIndent();

        r.Newline();

        wxArrayInt tabs;
        tabs.Add(400);
        tabs.Add(600);
        tabs.Add(800);
        tabs.Add(1000);
        wxTextAttrEx attr;
        attr.SetFlags(wxTEXT_ATTR_TABS);
        attr.SetTabs(tabs);
        r.SetDefaultStyle(attr);

        r.WriteText(wxT("This line contains tabs:\tFirst tab\tSecond tab\tThird tab"));

        r.Newline();
        r.WriteText(wxT("Other notable features of wxRichTextCtrl include:"));

        r.BeginSymbolBullet(wxT('*'), 100, 60);
        r.Newline();
        r.WriteText(wxT("Compatibility with wxTextCtrl API"));
        r.EndSymbolBullet();

        r.WriteText(
          wxT("\nNote: this content was generated programmatically and copied from the sample. The images were loaded "
              "from inline XPMs. Enjoy wxRichTextCtrl!"));

        r.EndSuppressUndo();
        r.Thaw();

        return richText;
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Text, "value");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Text, "value");
        return xfb;
    }
};

class HtmlWindowComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxHtmlWindow* hw = new wxHtmlWindow(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        wxString dummy_page(wxT("<b>wxHtmlWindow</b><br />") wxT("This is a dummy page.</body></html>"));

        hw->SetPage(dummy_page);

        return hw;
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        return xfb;
    }
};

class ToggleButtonComponent : public ComponentBase, public wxEvtHandler
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxString label = obj->GetPropertyAsString(_("label"));
        wxToggleButton* button = new wxToggleButton(
          (wxWindow*)parent, wxID_ANY, label, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        if (obj->GetPropertyAsInteger(_("markup")) != 0) {
            button->SetLabelMarkup(label);
        }

        if (!obj->IsPropertyNull(_("bitmap"))) {
            button->SetBitmap(obj->GetPropertyAsBitmap(_("bitmap")));
        }

        if (!obj->IsPropertyNull(_("disabled"))) {
            button->SetBitmapDisabled(obj->GetPropertyAsBitmap(_("disabled")));
        }

        if (!obj->IsPropertyNull(_("pressed"))) {
            button->SetBitmapPressed(obj->GetPropertyAsBitmap(_("pressed")));
        }

        if (!obj->IsPropertyNull(_("focus"))) {
            button->SetBitmapFocus(obj->GetPropertyAsBitmap(_("focus")));
        }

        if (!obj->IsPropertyNull(_("current"))) {
            button->SetBitmapCurrent(obj->GetPropertyAsBitmap(_("current")));
        }

        if (!obj->IsPropertyNull(_("position"))) {
            button->SetBitmapPosition(static_cast<wxDirection>(obj->GetPropertyAsInteger(_("position"))));
        }

        if (!obj->IsPropertyNull(_("margins"))) {
            button->SetBitmapMargins(obj->GetPropertyAsSize(_("margins")));
        }

        button->SetValue((obj->GetPropertyAsInteger(_("value")) != 0));
        button->Connect(
          wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(ToggleButtonComponent::OnToggle), NULL, this);
        return button;
    }

    void OnToggle(wxCommandEvent& event)
    {
        wxToggleButton* window = dynamic_cast<wxToggleButton*>(event.GetEventObject());
        if (0 != window) {
            wxString value;
            value.Printf(wxT("%i"), window->GetValue() ? 1 : 0);
            GetManager()->ModifyProperty(window, _("value"), value);
            window->SetFocus();
        }
    }


    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Text, "label");
        filter.AddProperty(XrcFilter::Type::Bool, "markup");
        filter.AddProperty(XrcFilter::Type::Bitmap, "bitmap");
        if (!obj->IsPropertyNull("disabled")) {
            filter.AddProperty(XrcFilter::Type::Bitmap, "disabled");
        }
        if (!obj->IsPropertyNull("pressed")) {
            filter.AddProperty(XrcFilter::Type::Bitmap, "pressed");
        }
        if (!obj->IsPropertyNull("focus")) {
            filter.AddProperty(XrcFilter::Type::Bitmap, "focus");
        }
        if (!obj->IsPropertyNull("current")) {
            filter.AddProperty(XrcFilter::Type::Bitmap, "current");
        }
        if (!obj->IsPropertyNull("position")) {
            filter.AddProperty(XrcFilter::Type::Option, "position", "bitmapposition");
        }
        if (!obj->IsPropertyNull("margins")) {
            filter.AddProperty(XrcFilter::Type::Size, "margins");
        }
        filter.AddProperty(XrcFilter::Type::Bool, "value", "checked");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Text, "label");
        filter.AddProperty(XrcFilter::Type::Bool, "markup");
        filter.AddProperty(XrcFilter::Type::Bitmap, "bitmap");
        filter.AddProperty(XrcFilter::Type::Bitmap, "disabled");
        filter.AddProperty(XrcFilter::Type::Bitmap, "pressed");
        filter.AddProperty(XrcFilter::Type::Bitmap, "focus");
        filter.AddProperty(XrcFilter::Type::Bitmap, "current");
        filter.AddProperty(XrcFilter::Type::Option, "bitmapposition", "position");
        filter.AddProperty(XrcFilter::Type::Size, "margins");
        filter.AddProperty(XrcFilter::Type::Bool, "checked", "value");
        return xfb;
    }
};

class BitmapToggleButtonComponent : public ComponentBase, public wxEvtHandler
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxBitmapToggleButton* button = new wxBitmapToggleButton(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsBitmap(_("bitmap")), obj->GetPropertyAsPoint(_("pos")),
          obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        // To stay in sync what the generator templates do apply the markup label here as well
        if (obj->GetPropertyAsInteger(_("markup")) != 0) {
            button->SetLabelMarkup(obj->GetPropertyAsString(_("label")));
        }

        if (!obj->IsPropertyNull(_("disabled"))) {
            button->SetBitmapDisabled(obj->GetPropertyAsBitmap(_("disabled")));
        }

        if (!obj->IsPropertyNull(_("pressed"))) {
            button->SetBitmapPressed(obj->GetPropertyAsBitmap(_("pressed")));
        }

        if (!obj->IsPropertyNull(_("focus"))) {
            button->SetBitmapFocus(obj->GetPropertyAsBitmap(_("focus")));
        }

        if (!obj->IsPropertyNull(_("current"))) {
            button->SetBitmapCurrent(obj->GetPropertyAsBitmap(_("current")));
        }

        if (!obj->IsPropertyNull(_("position"))) {
            button->SetBitmapPosition(static_cast<wxDirection>(obj->GetPropertyAsInteger(_("position"))));
        }

        if (!obj->IsPropertyNull(_("margins"))) {
            button->SetBitmapMargins(obj->GetPropertyAsSize(_("margins")));
        }

        button->SetValue((obj->GetPropertyAsInteger(_("value")) != 0));
        button->Connect(
          wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(ToggleButtonComponent::OnToggle), NULL, this);

        return button;
    }

    void OnToggle(wxCommandEvent& event)
    {
        wxBitmapToggleButton* window = dynamic_cast<wxBitmapToggleButton*>(event.GetEventObject());
        if (0 != window) {
            wxString value;
            value.Printf(wxT("%i"), window->GetValue() ? 1 : 0);
            GetManager()->ModifyProperty(window, _("value"), value);
            window->SetFocus();
        }
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Bitmap, "bitmap");
        if (!obj->IsPropertyNull("disabled")) {
            filter.AddProperty(XrcFilter::Type::Bitmap, "disabled");
        }
        if (!obj->IsPropertyNull("pressed")) {
            filter.AddProperty(XrcFilter::Type::Bitmap, "pressed");
        }
        if (!obj->IsPropertyNull("focus")) {
            filter.AddProperty(XrcFilter::Type::Bitmap, "focus");
        }
        if (!obj->IsPropertyNull("current")) {
            filter.AddProperty(XrcFilter::Type::Bitmap, "current");
        }
        if (!obj->IsPropertyNull("position")) {
            filter.AddProperty(XrcFilter::Type::Option, "position", "bitmapposition");
        }
        if (!obj->IsPropertyNull("margins")) {
            filter.AddProperty(XrcFilter::Type::Size, "margins");
        }
        filter.AddProperty(XrcFilter::Type::Bool, "value", "checked");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Bitmap, "bitmap");
        filter.AddProperty(XrcFilter::Type::Bitmap, "disabled");
        filter.AddProperty(XrcFilter::Type::Bitmap, "pressed");
        filter.AddProperty(XrcFilter::Type::Bitmap, "focus");
        filter.AddProperty(XrcFilter::Type::Bitmap, "current");
        filter.AddProperty(XrcFilter::Type::Option, "bitmapposition", "position");
        filter.AddProperty(XrcFilter::Type::Size, "margins");
        filter.AddProperty(XrcFilter::Type::Bool, "checked", "value");
        return xfb;
    }
};

class TreeCtrlComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        int style = obj->GetPropertyAsInteger(_("style"));
        wxTreeCtrl* tc = new wxTreeCtrl(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          style | obj->GetPropertyAsInteger(_("window_style")));

        // dummy nodes
        wxTreeItemId root = tc->AddRoot(wxT("root node"));
        wxTreeItemId node1 = tc->AppendItem(root, wxT("node1"));
        wxTreeItemId node2 = tc->AppendItem(root, wxT("node2"));
        wxTreeItemId node3 = tc->AppendItem(node2, wxT("node3"));
        if ((style & wxTR_HIDE_ROOT) == 0) {
            tc->Expand(root);
        }
        tc->Expand(node1);
        tc->Expand(node2);
        tc->Expand(node3);

        return tc;
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        return xfb;
    }
};

class ScrollBarComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxScrollBar* sb = new wxScrollBar(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        sb->SetScrollbar(
          obj->GetPropertyAsInteger(_T("value")), obj->GetPropertyAsInteger(_T("thumbsize")),
          obj->GetPropertyAsInteger(_T("range")), obj->GetPropertyAsInteger(_T("pagesize")));
        return sb;
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Integer, "value");
        filter.AddProperty(XrcFilter::Type::Integer, "thumbsize");
        filter.AddProperty(XrcFilter::Type::Integer, "range");
        filter.AddProperty(XrcFilter::Type::Integer, "pagesize");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Integer, "value");
        filter.AddProperty(XrcFilter::Type::Integer, "thumbsize");
        filter.AddProperty(XrcFilter::Type::Integer, "range");
        filter.AddProperty(XrcFilter::Type::Integer, "pagesize");
        return xfb;
    }
};

class SpinCtrlComponent : public ComponentBase, public wxEvtHandler
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        int max = obj->GetPropertyAsInteger(_("max"));
        int min = obj->GetPropertyAsInteger(_("min"));
        wxSpinCtrl* window = new wxSpinCtrl(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsString(_("value")), obj->GetPropertyAsPoint(_("pos")),
          obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")), min < max ? min : max,
          max, obj->GetPropertyAsInteger(_("initial")));

        window->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler(SpinCtrlComponent::OnSpin), NULL, this);
        return window;
    }

    void OnSpin(wxSpinEvent& event)
    {
        wxSpinCtrl* window = dynamic_cast<wxSpinCtrl*>(event.GetEventObject());
        if (0 != window) {
            wxString value;
            value.Printf(wxT("%i"), window->GetValue());
            GetManager()->ModifyProperty(window, _("initial"), value);
            window->SetFocus();
        }
    }

    void Cleanup(wxObject* obj) override
    {
        wxSpinCtrl* window = dynamic_cast<wxSpinCtrl*>(obj);
        if (0 != window) {
            window->Disconnect(
              wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler(SpinCtrlComponent::OnSpin), NULL, this);
        }
        ComponentBase::Cleanup(obj);
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Integer, "initial", "value");
        filter.AddProperty(XrcFilter::Type::Integer, "min");
        filter.AddProperty(XrcFilter::Type::Integer, "max");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        // TODO: XRC only supports the integral initial value, filter it twice to initialize the string initial value as well
        filter.AddProperty(XrcFilter::Type::String, "value");
        filter.AddProperty(XrcFilter::Type::Integer, "value", "initial");
        filter.AddProperty(XrcFilter::Type::Integer, "min");
        filter.AddProperty(XrcFilter::Type::Integer, "max");
        return xfb;
    }
};

class SpinCtrlDoubleComponent : public ComponentBase, public wxEvtHandler
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxSpinCtrlDouble* window = new wxSpinCtrlDouble(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsString(_("value")), obj->GetPropertyAsPoint(_("pos")),
          obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")),
          obj->GetPropertyAsFloat(_("min")), obj->GetPropertyAsFloat(_("max")), obj->GetPropertyAsFloat(_("initial")),
          obj->GetPropertyAsFloat(_("inc")));

        window->SetDigits(obj->GetPropertyAsInteger(_("digits")));

        window->Connect(
          wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, wxSpinEventHandler(SpinCtrlDoubleComponent::OnSpin), NULL, this);
        return window;
    }

    void OnSpin(wxSpinEvent& event)
    {
        wxSpinCtrlDouble* window = dynamic_cast<wxSpinCtrlDouble*>(event.GetEventObject());
        if (0 != window) {
            wxString value;
            value.Printf(wxT("%f"), window->GetValue());
            GetManager()->ModifyProperty(window, _("initial"), value);
            window->SetFocus();
        }
    }

    void Cleanup(wxObject* obj) override
    {
        wxSpinCtrlDouble* window = dynamic_cast<wxSpinCtrlDouble*>(obj);
        if (0 != window) {
            window->Disconnect(
              wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, wxSpinEventHandler(SpinCtrlDoubleComponent::OnSpin), NULL, this);
        }
        ComponentBase::Cleanup(obj);
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Float, "initial", "value");
        filter.AddProperty(XrcFilter::Type::Float, "min");
        filter.AddProperty(XrcFilter::Type::Float, "max");
        filter.AddProperty(XrcFilter::Type::Float, "inc");
        filter.AddProperty(XrcFilter::Type::Integer, "digits");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        // TODO: XRC only supports the float initial value, filter it twice to initialize the string initial value as well
        filter.AddProperty(XrcFilter::Type::String, "value");
        filter.AddProperty(XrcFilter::Type::Float, "value", "initial");
        filter.AddProperty(XrcFilter::Type::Float, "min");
        filter.AddProperty(XrcFilter::Type::Float, "max");
        filter.AddProperty(XrcFilter::Type::Float, "inc");
        filter.AddProperty(XrcFilter::Type::Integer, "digits");
        return xfb;
    }
};

class SpinButtonComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        return new wxSpinButton(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        return xfb;
    }
};

class CheckListBoxComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxArrayString choices(obj->GetPropertyAsArrayString(_("choices")));
        wxCheckListBox* cl = new wxCheckListBox(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")), choices,
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        return cl;
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::TextList, "choices", "content");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::TextList, "content", "choices");
        return xfb;
    }
};

class GridComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxGrid* grid = new wxGrid(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("window_style")));

        grid->CreateGrid(obj->GetPropertyAsInteger(_("rows")), obj->GetPropertyAsInteger(_("cols")));

        grid->EnableDragColMove(obj->GetPropertyAsInteger(_("drag_col_move")) != 0);
        grid->EnableDragColSize(obj->GetPropertyAsInteger(_("drag_col_size")) != 0);
        grid->EnableDragGridSize(obj->GetPropertyAsInteger(_("drag_grid_size")) != 0);
        grid->EnableDragRowSize(obj->GetPropertyAsInteger(_("drag_row_size")) != 0);
        grid->EnableEditing(obj->GetPropertyAsInteger(_("editing")) != 0);
        grid->EnableGridLines(obj->GetPropertyAsInteger(_("grid_lines")) != 0);
        if (!obj->IsPropertyNull(_("grid_line_color"))) {
            grid->SetGridLineColour(obj->GetPropertyAsColour(_("grid_line_color")));
        }
        grid->SetMargins(obj->GetPropertyAsInteger(_("margin_width")), obj->GetPropertyAsInteger(_("margin_height")));

        // Label Properties
        grid->SetColLabelAlignment(
          obj->GetPropertyAsInteger(_("col_label_horiz_alignment")),
          obj->GetPropertyAsInteger(_("col_label_vert_alignment")));

        wxArrayString columnLabels = obj->GetPropertyAsArrayString(_("col_label_values"));
        for (int i = 0; i < (int)columnLabels.size() && i < grid->GetNumberCols(); ++i) {
            grid->SetColLabelValue(i, columnLabels[i]);
        }

        if (!obj->IsPropertyNull(_("col_label_size"))) {
            grid->SetColLabelSize(obj->GetPropertyAsInteger(_("col_label_size")));
        }

        wxArrayInt columnSizes = obj->GetPropertyAsArrayInt(_("column_sizes"));
        for (int i = 0; i < (int)columnSizes.size() && i < grid->GetNumberCols(); ++i) {
            grid->SetColSize(i, columnSizes[i]);
        }

        grid->SetRowLabelAlignment(
          obj->GetPropertyAsInteger(_("row_label_horiz_alignment")),
          obj->GetPropertyAsInteger(_("row_label_vert_alignment")));

        wxArrayString rowLabels = obj->GetPropertyAsArrayString(_("row_label_values"));
        for (int i = 0; i < (int)rowLabels.size() && i < grid->GetNumberRows(); ++i) {
            grid->SetRowLabelValue(i, rowLabels[i]);
        }

        if (!obj->IsPropertyNull(_("row_label_size"))) {
            grid->SetRowLabelSize(obj->GetPropertyAsInteger(_("row_label_size")));
        }

        wxArrayInt rowSizes = obj->GetPropertyAsArrayInt(_("row_sizes"));
        for (int i = 0; i < (int)rowSizes.size() && i < grid->GetNumberRows(); ++i) {
            grid->SetRowSize(i, rowSizes[i]);
        }

        if (!obj->IsPropertyNull(_("label_bg"))) {
            grid->SetLabelBackgroundColour(obj->GetPropertyAsColour(_("label_bg")));
        }
        if (!obj->IsPropertyNull(_("label_text"))) {
            grid->SetLabelTextColour(obj->GetPropertyAsColour(_("label_text")));
        }
        if (!obj->IsPropertyNull(_("label_font"))) {
            grid->SetLabelFont(obj->GetPropertyAsFont(_("label_font")));
        }

        // Default Cell Properties
        grid->SetDefaultCellAlignment(
          obj->GetPropertyAsInteger(_("cell_horiz_alignment")), obj->GetPropertyAsInteger(_("cell_vert_alignment")));

        if (!obj->IsPropertyNull(_("cell_bg"))) {
            grid->SetDefaultCellBackgroundColour(obj->GetPropertyAsColour(_("cell_bg")));
        }
        if (!obj->IsPropertyNull(_("cell_text"))) {
            grid->SetDefaultCellTextColour(obj->GetPropertyAsColour(_("cell_text")));
        }
        if (!obj->IsPropertyNull(_("cell_font"))) {
            grid->SetDefaultCellFont(obj->GetPropertyAsFont(_("cell_font")));
        }

        // Example Cell Values
        for (int col = 0; col < grid->GetNumberCols(); ++col) {
            for (int row = 0; row < grid->GetNumberRows(); ++row) {
                grid->SetCellValue(row, col, grid->GetColLabelValue(col) + wxT("-") + grid->GetRowLabelValue(row));
            }
        }

        if (obj->GetPropertyAsInteger(_("autosize_rows")) != 0) {
            grid->AutoSizeRows();
        }
        if (obj->GetPropertyAsInteger(_("autosize_cols")) != 0) {
            grid->AutoSizeColumns();
        }

        grid->PushEventHandler(new ComponentEvtHandler(grid, GetManager()));

        return grid;
    }

    void Cleanup(wxObject* obj) override
    {
        auto* window = wxDynamicCast(obj, wxGrid);
        if (window) {
            window->PopEventHandler(true);
        }
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        return xfb;
    }
};


class PickerComponentBase : public ComponentBase, public wxEvtHandler
{
public:
    void OnLeftClick(wxMouseEvent& event)
    {
        wxWindow* window = dynamic_cast<wxWindow*>(event.GetEventObject());
        wxPickerBase* picker = dynamic_cast<wxPickerBase*>(window->GetParent());
        if (0 != picker) {
            if (!GetManager()->SelectObject(picker)) {
                event.Skip();
            }
        }
    }

    void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override
    {
        wxPickerBase* picker = dynamic_cast<wxPickerBase*>(wxobject);
        if (picker != 0) {
            picker->GetPickerCtrl()->Connect(
              wxEVT_LEFT_DOWN, wxMouseEventHandler(PickerComponentBase::OnLeftClick), NULL, this);

            wxTextCtrl* text = picker->GetTextCtrl();
            if (0 != text) {
                text->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(PickerComponentBase::OnLeftClick), NULL, this);
            }
        }
    }

    void Cleanup(wxObject* obj) override
    {
        wxPickerBase* picker = dynamic_cast<wxPickerBase*>(obj);
        if (picker != 0) {
            picker->GetPickerCtrl()->Disconnect(
              wxEVT_LEFT_DOWN, wxMouseEventHandler(PickerComponentBase::OnLeftClick), NULL, this);

            wxTextCtrl* text = picker->GetTextCtrl();
            if (0 != text) {
                text->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(PickerComponentBase::OnLeftClick), NULL, this);
            }
        }
        ComponentBase::Cleanup(obj);
    }
};

class ColourPickerComponent : public PickerComponentBase
{
private:
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxColourPickerCtrl* colourpicker = new wxColourPickerCtrl(
          (wxWindow*)parent, obj->GetPropertyAsInteger(_("id")), obj->GetPropertyAsColour(_("colour")),
          obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        colourpicker->PushEventHandler(new ComponentEvtHandler(colourpicker, GetManager()));
        return colourpicker;
    }

    void Cleanup(wxObject* obj) override
    {
        auto* window = wxDynamicCast(obj, wxColourPickerCtrl);
        if (window) {
            window->PopEventHandler(true);
        }
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Colour, "colour", "value");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Colour, "value", "colour");
        return xfb;
    }
};

class FontPickerComponent : public PickerComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxFontPickerCtrl* picker = new wxFontPickerCtrl(
          (wxWindow*)parent, obj->GetPropertyAsInteger(_("id")), obj->GetPropertyAsFont(_("value")),
          obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        if (!obj->IsPropertyNull(_("max_point_size"))) {
            picker->SetMaxPointSize(obj->GetPropertyAsInteger(_("max_point_size")));
        }

        picker->PushEventHandler(new ComponentEvtHandler(picker, GetManager()));
        return picker;
    }

    void Cleanup(wxObject* obj) override
    {
        auto* window = wxDynamicCast(obj, wxFontPickerCtrl);
        if (window) {
            window->PopEventHandler(true);
        }
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        if (!obj->IsPropertyNull("value")) {
            filter.AddProperty(XrcFilter::Type::Font, "value");
        }
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Font, "value");
        return xfb;
    }
};

class FilePickerComponent : public PickerComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxFilePickerCtrl* picker = new wxFilePickerCtrl(
          (wxWindow*)parent, obj->GetPropertyAsInteger(_("id")), obj->GetPropertyAsString(_("value")),
          obj->GetPropertyAsString(_("message")), obj->GetPropertyAsString(_("wildcard")),
          obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        picker->PushEventHandler(new ComponentEvtHandler(picker, GetManager()));
        return picker;
    }

    void Cleanup(wxObject* obj) override
    {
        auto* window = wxDynamicCast(obj, wxFilePickerCtrl);
        if (window) {
            window->PopEventHandler(true);
        }
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::String, "value");
        filter.AddProperty(XrcFilter::Type::Text, "message");
        filter.AddProperty(XrcFilter::Type::Text, "wildcard");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::String, "value");
        filter.AddProperty(XrcFilter::Type::Text, "message");
        filter.AddProperty(XrcFilter::Type::Text, "wildcard");
        return xfb;
    }
};

class DirPickerComponent : public PickerComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxDirPickerCtrl* picker = new wxDirPickerCtrl(
          (wxWindow*)parent, obj->GetPropertyAsInteger(_("id")), obj->GetPropertyAsString(_("value")),
          obj->GetPropertyAsString(_("message")), obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        picker->PushEventHandler(new ComponentEvtHandler(picker, GetManager()));
        return picker;
    }

    void Cleanup(wxObject* obj) override
    {
        auto* window = wxDynamicCast(obj, wxDirPickerCtrl);
        if (window) {
            window->PopEventHandler(true);
        }
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::String, "value");
        filter.AddProperty(XrcFilter::Type::Text, "message");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::String, "value");
        filter.AddProperty(XrcFilter::Type::Text, "message");
        return xfb;
    }
};

class HyperlinkComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxHyperlinkCtrl* ctrl = new wxHyperlinkCtrl(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsString(_("label")), obj->GetPropertyAsString(_("url")),
          obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        if (!obj->IsPropertyNull(_("hover_color"))) {
            ctrl->SetHoverColour(obj->GetPropertyAsColour(_("hover_color")));
        }
        if (!obj->IsPropertyNull(_("normal_color"))) {
            ctrl->SetNormalColour(obj->GetPropertyAsColour(_("normal_color")));
        }
        if (!obj->IsPropertyNull(_("visited_color"))) {
            ctrl->SetVisitedColour(obj->GetPropertyAsColour(_("visited_color")));
        }

        return ctrl;
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Text, "label");
        filter.AddProperty(XrcFilter::Type::String, "url");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Text, "label");
        filter.AddProperty(XrcFilter::Type::String, "url");
        return xfb;
    }
};

class GenericDirCtrlComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxGenericDirCtrl* ctrl = new wxGenericDirCtrl(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsString(_("defaultfolder")), obj->GetPropertyAsPoint(_("pos")),
          obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")),
          obj->GetPropertyAsString(_("filter")), obj->GetPropertyAsInteger(_("defaultfilter")));

        ctrl->ShowHidden(obj->GetPropertyAsInteger(_("show_hidden")) != 0);
        ctrl->GetTreeCtrl()->PushEventHandler(new GenericDirCtrlEvtHandler(ctrl, GetManager()));
        return ctrl;
    }

    void Cleanup(wxObject* obj) override
    {
        auto* window = wxDynamicCast(obj, wxGenericDirCtrl);
        if (window) {
            window->GetTreeCtrl()->PopEventHandler(true);
        }
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::String, "defaultfolder");
        filter.AddProperty(XrcFilter::Type::Text, "filter");
        filter.AddProperty(XrcFilter::Type::Integer, "defaultfilter");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::String, "defaultfolder");
        filter.AddProperty(XrcFilter::Type::Text, "filter");
        filter.AddProperty(XrcFilter::Type::Integer, "defaultfilter");
        return xfb;
    }
};

class CustomControlComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* /*obj*/, wxObject* parent) override
    {
        return new wxPanel((wxWindow*)parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj, obj->GetPropertyAsString("class"));
        return xrc;
    }
};

class CustomCodeComponent : public ComponentBase
{
};

class SearchCtrlComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxSearchCtrl* sc = new wxSearchCtrl(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsString(_("value")), obj->GetPropertyAsPoint(_("pos")),
          obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        if (!obj->IsPropertyNull(_("search_button"))) {
            sc->ShowSearchButton(obj->GetPropertyAsInteger(_("search_button")) != 0);
        }

        if (!obj->IsPropertyNull(_("cancel_button"))) {
            sc->ShowCancelButton(obj->GetPropertyAsInteger(_("cancel_button")) != 0);
        }

        sc->PushEventHandler(new ComponentEvtHandler(sc, GetManager()));

        return sc;
    }

    void Cleanup(wxObject* obj) override
    {
        auto* window = wxDynamicCast(obj, wxSearchCtrl);
        if (window) {
            window->PopEventHandler(true);
        }
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Text, "value");
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        filter.AddProperty(XrcFilter::Type::Text, "value");
        return xfb;
    }
};

#ifdef USE_MEDIACTRL
class MediaCtrlComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxMediaCtrl* mc = new wxMediaCtrl(
          (wxWindow*)parent, wxID_ANY, wxT(""), obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        if (!obj->IsPropertyNull(_("file"))) {
            if (mc->Load(obj->GetPropertyAsString(_("file")))) {
                if (!obj->IsPropertyNull(_("playback_rate")))
                    mc->SetPlaybackRate(obj->GetPropertyAsFloat(_("playback_rate")));
                if (
                  !obj->IsPropertyNull(_("volume")) && (obj->GetPropertyAsFloat(_("volume")) >= 0) &&
                  (obj->GetPropertyAsFloat(_("volume")) <= 1))
                    mc->SetPlaybackRate(obj->GetPropertyAsFloat(_("volume")));
                if (!obj->IsPropertyNull(_("player_controls"))) {
                    if (obj->GetPropertyAsString(_("player_controls")) == wxT("STEP"))
                        mc->ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_STEP);
                    if (obj->GetPropertyAsString(_("player_controls")) == wxT("VOLUME"))
                        mc->ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_VOLUME);
                    if (obj->GetPropertyAsString(_("player_controls")) == wxT("DEFAULT"))
                        mc->ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_DEFAULT);
                    if (obj->GetPropertyAsString(_("player_controls")) == wxT("NONE"))
                        mc->ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_NONE);
                }

                if (!obj->IsPropertyNull(_("play")) && (obj->GetPropertyAsInteger(_("play")) == 1))
                    mc->Play();
                else
                    mc->Stop();

                // GetManager()->ModifyProperty( m_window, wxT("size"), mc->GetBestSize() );
            }
        }

        if (!obj->IsPropertyNull(_("style")))
            mc->ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_STEP);

        mc->PushEventHandler(new ComponentEvtHandler(mc, GetManager()));

        return mc;
    }

    void Cleanup(wxObject* obj) override
    {
        auto* window = wxDynamicCast(obj, wxMediaCtrl);
        if (window) {
            window->PopEventHandler(true);
        }
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        return xfb;
    }
};
#endif

class TimerComponent : public ComponentBase
{
public:
};

class PropertyGridComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxPropertyGrid* pg = new wxPropertyGrid(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(wxT("pos")), obj->GetPropertyAsSize(wxT("size")),
          obj->GetPropertyAsInteger(wxT("style")) | obj->GetPropertyAsInteger(wxT("window_style")));

        if (!obj->GetPropertyAsString(wxT("extra_style")).empty()) {
            pg->SetExtraStyle(obj->GetPropertyAsInteger(wxT("extra_style")));
        }

        return pg;
    }

    /*void Cleanup( wxObject* )
    {
            // Prevent assert for missing event handler
    }*/

    void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override
    {
        wxPropertyGrid* pg = wxDynamicCast(wxobject, wxPropertyGrid);
        if (NULL == pg) {
            // very very strange
            return;
        }

        size_t count = GetManager()->GetChildCount(wxobject);
        for (size_t i = 0; i < count; ++i) {
            wxObject* child = GetManager()->GetChild(wxobject, i);
            IObject* childObj = GetManager()->GetIObject(child);
            if (childObj->GetClassName() == _("propGridItem")) {
                auto propName = childObj->GetPropertyAsString(_("prop_name"));
                if (childObj->GetPropertyAsString(_("type")) == _("Category")) {
                    pg->Append(new wxPropertyCategory(
                      childObj->GetPropertyAsString(_("label")), !propName.empty() ? propName : wxPG_LABEL));
                } else {
                    wxPGProperty* prop = wxDynamicCast(
                      wxCreateDynamicObject(wxT("wx") + (childObj->GetPropertyAsString(_("type"))) + wxT("Property")),
                      wxPGProperty);
                    if (prop) {
                        prop->SetLabel(childObj->GetPropertyAsString(_("label")));
                        if (!propName.empty()) {
                            prop->SetName(propName);
                        }
                        pg->Append(prop);

                        if (childObj->GetPropertyAsString(_("help")) != wxEmptyString) {
                            pg->SetPropertyHelpString(prop, childObj->GetPropertyAsString(_("help")));
                        }
                    }
                }
            }
        }
    }
};

class PropertyGridManagerComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxPropertyGridManager* pgman = new wxPropertyGridManager(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(wxT("pos")), obj->GetPropertyAsSize(wxT("size")),
          obj->GetPropertyAsInteger(wxT("style")) | obj->GetPropertyAsInteger(wxT("window_style")));

        if (!obj->GetPropertyAsString(wxT("extra_style")).empty()) {
            pgman->SetExtraStyle(obj->GetPropertyAsInteger(wxT("extra_style")));
        }

        pgman->ShowHeader(obj->GetPropertyAsInteger(wxT("show_header")) != 0);

        // Adding a page sets target page to the one added, so
        // we don't have to call SetTargetPage if we are filling
        // it right after adding.
        /*wxPropertyGridPage* pg = pgman->AddPage( _("First Page") );

        pg->Append( new wxPropertyCategory( _("Sample Category") ) );

        // Add string property
        wxPGProperty *id = pg->Append( new wxStringProperty( _("Label"), wxPG_LABEL, _("Initial Value") ) );
        pg->SetPropertyHelpString( id, _("A string property") );

        // Add int property
        pg->Append( new wxIntProperty ( wxT("IntProperty"), wxPG_LABEL, 12345678 ) );

        // Add float property (value type is actually double)
        pg->Append( new wxFloatProperty ( wxT("FloatProperty"), wxPG_LABEL, 12345.678 ) );

        // Add a bool property
        pg->Append( new wxBoolProperty ( wxT("BoolProperty"), wxPG_LABEL, false ) );
        pg->Append( new wxBoolProperty ( wxT("BoolPropertyAsCheckbox"), wxPG_LABEL, true ) );
        pg->SetPropertyAttribute( wxT("BoolPropertyAsCheckbox"), wxPG_BOOL_USE_CHECKBOX, (long)1 );

        // Add an enum property
        wxArrayString strings;
        strings.Add( _("Herbivore") );
        strings.Add( _("Carnivore") );
        strings.Add( _("Omnivore") );

        wxArrayInt indexes;
        indexes.Add( 0 );
        indexes.Add( 1 );
        indexes.Add( 2 );

        pg->Append( new wxEnumProperty( wxT("EnumProperty"), wxPG_LABEL, strings, indexes, 0 ) );

        pg->Append( new wxPropertyCategory( _("Low Priority Properties") ) );

        // A string property that can be edited in a separate editor dialog.
        pg->Append( new wxLongStringProperty( wxT("LongStringProperty"), wxPG_LABEL,
                                                                                  wxString(_("This is much longer string
        than the ") ) + wxString(_("first one. Edit it by clicking the button.") ) ) );

        // String editor with dir selector button.
        pg->Append( new wxDirProperty( wxT("DirProperty"), wxPG_LABEL, ::wxGetUserHome() ) );

        // A file selector property.
        pg->Append( new wxFileProperty( wxT("FileProperty"), wxPG_LABEL, wxEmptyString ) );

        wxPropertyGridPage* pg2 = pgman->AddPage( _("Second Page") );

        pg2->Append( new wxPropertyCategory( _("Sample Parent Property"), wxPG_LABEL ) );

        wxPGProperty* carProp2 = pg2->Append( new wxStringProperty( _("Car"), wxPG_LABEL, wxT("<composed>") ) );
        pg2->AppendIn( carProp2, new wxStringProperty( _("Model"), wxPG_LABEL, wxT("Lamborghini Diablo SV") ) );
        pg2->AppendIn( carProp2, new wxIntProperty( _("Engine Size (cc)"), wxPG_LABEL, 5707) );

        wxPGProperty* speedsProp2 = pg2->AppendIn( carProp2, new wxStringProperty( _("Speeds"), wxPG_LABEL,
        wxT("<composed>") ) ); pg2->AppendIn( speedsProp2, new wxIntProperty( _("Max. Speed (mph)"), wxPG_LABEL, 300 )
        ); pg2->AppendIn( speedsProp2, new wxFloatProperty( _("0-100 mph (sec)"), wxPG_LABEL, 3.9 ) ); pg2->AppendIn(
        speedsProp2, new wxFloatProperty( _("1/4 mile (sec)"), wxPG_LABEL, 8.6) );

        pg2->AppendIn( carProp2, new wxIntProperty( _("Price ($)"), wxPG_LABEL, 300000 ) );

        if ( obj->GetPropertyAsInteger( wxT("include_advanced") ) )
        {
                pg2->Append( new wxPropertyCategory( _("Advanced Properties"), wxPG_LABEL ) );
                // wxArrayStringProperty embeds a wxArrayString.
                pg2->Append( new wxArrayStringProperty( _("Example of ArrayStringProperty"), wxT("ArrayStringProp") ) );

                // Image file property. Wildcard is auto-generated from available
                // image handlers, so it is not set this time.
                pg2->Append( new wxImageFileProperty( _("Example of ImageFileProperty"), wxT("ImageFileProp") ) );

                // Font property has sub-properties.
                pg2->Append( new wxFontProperty( _("Font"), wxPG_LABEL ) );

                // Colour property with arbitrary colour.
                pg2->Append( new wxColourProperty( _("My Colour 1"), wxPG_LABEL, wxColour( 242, 109, 0 ) ) );

                // System colour property.
                pg2->Append( new wxSystemColourProperty( _("My SysColour 1"), wxPG_LABEL, wxSystemSettings::GetColour(
        wxSYS_COLOUR_WINDOW ) ) );

                // System colour property with custom colour.
                pg2->Append( new wxSystemColourProperty( _("My SysColour 2"), wxPG_LABEL, wxColour( 0, 200, 160 ) ) );

                // Cursor property
                pg2->Append( new wxCursorProperty( _("My Cursor"), wxPG_LABEL, wxCURSOR_ARROW ) );
        }*/

        return pgman;
    }
    /*
            void Cleanup( wxObject* )
            {
                    // Prevent assert for missing event handler
            }*/

    void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override
    {
        wxPropertyGridManager* pgm = wxDynamicCast(wxobject, wxPropertyGridManager);
        if (NULL == pgm) {
            // very very strange
            return;
        }

        size_t count = GetManager()->GetChildCount(wxobject);
        for (size_t i = 0; i < count; ++i) {
            wxObject* child = GetManager()->GetChild(wxobject, i);
            IObject* childObj = GetManager()->GetIObject(child);
            if (childObj->GetClassName() == _("propGridPage")) {
                wxPropertyGridPage* page =
                  pgm->AddPage(childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsBitmap(_("bitmap")));

                for (size_t j = 0; j < childObj->GetChildCount(); ++j) {
                    auto* innerChildObj = childObj->GetChildObject(j);
                    if (innerChildObj->GetClassName() == _("propGridItem")) {
                        auto propName = innerChildObj->GetPropertyAsString(_("prop_name"));
                        if (innerChildObj->GetPropertyAsString(_("type")) == _("Category")) {
                            page->Append(new wxPropertyCategory(
                              innerChildObj->GetPropertyAsString(_("label")),
                              !propName.empty() ? propName : wxPG_LABEL));
                        } else {
                            wxPGProperty* prop = wxDynamicCast(
                              wxCreateDynamicObject(
                                wxT("wx") + (innerChildObj->GetPropertyAsString(_("type"))) + wxT("Property")),
                              wxPGProperty);
                            if (prop) {
                                prop->SetLabel(innerChildObj->GetPropertyAsString(_("label")));
                                if (!propName.empty()) {
                                    prop->SetName(propName);
                                }
                                page->Append(prop);

                                if (innerChildObj->GetPropertyAsString(_("help")) != wxEmptyString) {
                                    page->SetPropertyHelpString(prop, innerChildObj->GetPropertyAsString(_("help")));
                                }
                            }
                        }
                    }
                }
            }
        }

        if (count) {
            pgm->SelectPage(0);
        }

        pgm->Update();
    }
};

class PropertyGridItemComponent : public ComponentBase
{
};
class PropertyGridPageComponent : public ComponentBase
{
};

class StyledTextComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxStyledTextCtrl* m_code = new wxStyledTextCtrl(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("window_style")), obj->GetPropertyAsString(_("name")));

        // Line Numbers
        if (0 != obj->GetPropertyAsInteger(_("line_numbers"))) {
            m_code->SetMarginType(0, wxSTC_MARGIN_NUMBER);
            m_code->SetMarginWidth(0, m_code->TextWidth(wxSTC_STYLE_LINENUMBER, wxT("_99999")));
        } else {
            m_code->SetMarginWidth(0, 0);
        }

        // markers
        m_code->MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS);
        m_code->MarkerSetBackground(wxSTC_MARKNUM_FOLDER, wxColour(wxT("BLACK")));
        m_code->MarkerSetForeground(wxSTC_MARKNUM_FOLDER, wxColour(wxT("WHITE")));
        m_code->MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS);
        m_code->MarkerSetBackground(wxSTC_MARKNUM_FOLDEROPEN, wxColour(wxT("BLACK")));
        m_code->MarkerSetForeground(wxSTC_MARKNUM_FOLDEROPEN, wxColour(wxT("WHITE")));
        m_code->MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_EMPTY);
        m_code->MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUS);
        m_code->MarkerSetBackground(wxSTC_MARKNUM_FOLDEREND, wxColour(wxT("BLACK")));
        m_code->MarkerSetForeground(wxSTC_MARKNUM_FOLDEREND, wxColour(wxT("WHITE")));
        m_code->MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUS);
        m_code->MarkerSetBackground(wxSTC_MARKNUM_FOLDEROPENMID, wxColour(wxT("BLACK")));
        m_code->MarkerSetForeground(wxSTC_MARKNUM_FOLDEROPENMID, wxColour(wxT("WHITE")));
        m_code->MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_EMPTY);
        m_code->MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_EMPTY);

        // folding
        if (0 != obj->GetPropertyAsInteger(_("folding"))) {
            m_code->SetMarginType(1, wxSTC_MARGIN_SYMBOL);
            m_code->SetMarginMask(1, wxSTC_MASK_FOLDERS);
            m_code->SetMarginWidth(1, 16);
            m_code->SetMarginSensitive(1, true);

            m_code->SetProperty(wxT("fold"), wxT("1"));
            m_code->SetFoldFlags(wxSTC_FOLDFLAG_LINEBEFORE_CONTRACTED | wxSTC_FOLDFLAG_LINEAFTER_CONTRACTED);
        } else {
            m_code->SetMarginWidth(1, 0);
        }
        m_code->SetIndentationGuides(obj->GetPropertyAsInteger(_("indentation_guides")));

        m_code->SetMarginWidth(2, 0);

        m_code->SetLexer(wxSTC_LEX_CPP);
        m_code->SetKeyWords(0, wxT("asm auto bool break case catch char class const const_cast \
							   continue default delete do double dynamic_cast else enum explicit \
							   export extern false float for friend goto if inline int long \
							   mutable namespace new operator private protected public register \
							   reinterpret_cast return short signed sizeof static static_cast \
							   struct switch template this throw true try typedef typeid \
							   typename union unsigned using virtual void volatile wchar_t \
							   while"));

        wxFont font(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
        if (!obj->GetPropertyAsString(_("font")).empty()) {
            font = obj->GetPropertyAsFont(_("font"));
        }

        m_code->StyleSetFont(wxSTC_STYLE_DEFAULT, font);

        m_code->StyleClearAll();
        m_code->StyleSetBold(wxSTC_C_WORD, true);
        m_code->StyleSetForeground(wxSTC_C_WORD, *wxBLUE);
        m_code->StyleSetForeground(wxSTC_C_STRING, *wxRED);
        m_code->StyleSetForeground(wxSTC_C_STRINGEOL, *wxRED);
        m_code->StyleSetForeground(wxSTC_C_PREPROCESSOR, wxColour(49, 106, 197));
        m_code->StyleSetForeground(wxSTC_C_COMMENT, wxColour(0, 128, 0));
        m_code->StyleSetForeground(wxSTC_C_COMMENTLINE, wxColour(0, 128, 0));
        m_code->StyleSetForeground(wxSTC_C_COMMENTDOC, wxColour(0, 128, 0));
        m_code->StyleSetForeground(wxSTC_C_COMMENTLINEDOC, wxColour(0, 128, 0));
        m_code->StyleSetForeground(wxSTC_C_NUMBER, *wxBLUE);
        m_code->SetUseTabs((0 != obj->GetPropertyAsInteger(_("use_tabs"))));
        m_code->SetTabWidth(obj->GetPropertyAsInteger(_("tab_width")));
        m_code->SetTabIndents((0 != obj->GetPropertyAsInteger(_("tab_indents"))));
        m_code->SetBackSpaceUnIndents((0 != obj->GetPropertyAsInteger(_("backspace_unindents"))));
        m_code->SetIndent(obj->GetPropertyAsInteger(_("tab_width")));
        m_code->SetSelBackground(true, wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
        m_code->SetSelForeground(true, wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
        m_code->SetViewEOL((0 != obj->GetPropertyAsInteger(_("view_eol"))));
        m_code->SetViewWhiteSpace(obj->GetPropertyAsInteger(_("view_whitespace")));

        m_code->SetCaretWidth(2);

        m_code->SetText(wxT("/** Sample Class to Display wxScintilla */\n") wxT("class ScintillaSampleCode\n")
                          wxT("{\n") wxT("private:\n") wxT("\tint m_privateMember;\n\n") wxT("public:\n\n")
                            wxT("\t// Sample Member Function\n") wxT("\tint SampleFunction( int sample = 0 )\n")
                              wxT("\t{\n") wxT("\t\treturn sample;\n") wxT("\t}\n") wxT("};\n"));

        m_code->PushEventHandler(new ComponentEvtHandler(m_code, GetManager()));

        return m_code;
    }

    void Cleanup(wxObject* obj) override
    {
        auto* window = wxDynamicCast(obj, wxStyledTextCtrl);
        if (window) {
            window->PopEventHandler(true);
        }
    }
};

class DataViewModel : public wxDataViewModel
{
public:
    unsigned int GetChildren(const wxDataViewItem&, wxDataViewItemArray& /*children*/) const override { return 0; }
    unsigned int GetColumnCount() const override { return 0; }
    wxString GetColumnType(unsigned int /*col*/) const override { return wxVariant("Dummy").GetType(); }
    wxDataViewItem GetParent(const wxDataViewItem&) const override { return wxDataViewItem(NULL); }
    bool IsContainer(const wxDataViewItem&) const override { return false; }
    void GetValue(wxVariant&, const wxDataViewItem&, unsigned int /*col*/) const override {}
    bool SetValue(const wxVariant&, const wxDataViewItem&, unsigned int /*col*/) override { return true; }
};

class DataViewCtrl : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxDataViewCtrl* dataViewCtrl = new wxDataViewCtrl(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("window_style")));

        wxObjectDataPtr<DataViewModel> model;
        model = new DataViewModel;
        dataViewCtrl->AssociateModel(model.get());

        return dataViewCtrl;
    }

    void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override
    {
        wxDataViewCtrl* list = wxDynamicCast(wxobject, wxDataViewCtrl);
        if (NULL == list) {
            // very very strange
            return;
        }
        size_t count = GetManager()->GetChildCount(wxobject);
        for (size_t i = 0; i < count; ++i) {
            wxObject* child = GetManager()->GetChild(wxobject, i);
            IObject* childObj = GetManager()->GetIObject(child);
            if (childObj->GetClassName() == _("dataViewColumn")) {
                if (childObj->GetPropertyAsString(_("type")) == _("Text")) {
                    auto* col = list->AppendTextColumn(
                      childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsInteger(_("model_column")),
                      static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
                      childObj->GetPropertyAsInteger(_("width")),
                      static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
                      childObj->GetPropertyAsInteger(_("flags")));
                    if (!childObj->IsPropertyNull(_("ellipsize"))) {
                        col->GetRenderer()->EnableEllipsize(
                          static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
                    }
                } else if (childObj->GetPropertyAsString(_("type")) == _("Toggle")) {
                    auto* col = list->AppendToggleColumn(
                      childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsInteger(_("model_column")),
                      static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
                      childObj->GetPropertyAsInteger(_("width")),
                      static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
                      childObj->GetPropertyAsInteger(_("flags")));
                    if (!childObj->IsPropertyNull(_("ellipsize"))) {
                        col->GetRenderer()->EnableEllipsize(
                          static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
                    }
                } else if (childObj->GetPropertyAsString(_("type")) == _("Progress")) {
                    auto* col = list->AppendProgressColumn(
                      childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsInteger(_("model_column")),
                      static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
                      childObj->GetPropertyAsInteger(_("width")),
                      static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
                      childObj->GetPropertyAsInteger(_("flags")));
                    if (!childObj->IsPropertyNull(_("ellipsize"))) {
                        col->GetRenderer()->EnableEllipsize(
                          static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
                    }
                } else if (childObj->GetPropertyAsString(_("type")) == _("IconText")) {
                    auto* col = list->AppendIconTextColumn(
                      childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsInteger(_("model_column")),
                      static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
                      childObj->GetPropertyAsInteger(_("width")),
                      static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
                      childObj->GetPropertyAsInteger(_("flags")));
                    if (!childObj->IsPropertyNull(_("ellipsize"))) {
                        col->GetRenderer()->EnableEllipsize(
                          static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
                    }
                } else if (childObj->GetPropertyAsString(_("type")) == _("Date")) {
                    auto* col = list->AppendDateColumn(
                      childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsInteger(_("model_column")),
                      static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
                      childObj->GetPropertyAsInteger(_("width")),
                      static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
                      childObj->GetPropertyAsInteger(_("flags")));
                    if (!childObj->IsPropertyNull(_("ellipsize"))) {
                        col->GetRenderer()->EnableEllipsize(
                          static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
                    }
                } else if (childObj->GetPropertyAsString(_("type")) == _("Bitmap")) {
                    auto* col = list->AppendBitmapColumn(
                      childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsInteger(_("model_column")),
                      static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
                      childObj->GetPropertyAsInteger(_("width")),
                      static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
                      childObj->GetPropertyAsInteger(_("flags")));
                    if (!childObj->IsPropertyNull(_("ellipsize"))) {
                        col->GetRenderer()->EnableEllipsize(
                          static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
                    }
                }
            }
        }
    }
};

class DataViewTreeCtrl : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxDataViewTreeCtrl* dataViewTreeCtrl = new wxDataViewTreeCtrl(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("window_style")));

        return dataViewTreeCtrl;
    }
};

class DataViewListCtrl : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxDataViewListCtrl* dataViewListCtrl = new wxDataViewListCtrl(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("window_style")));

        return dataViewListCtrl;
    }

    void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override
    {
        wxDataViewListCtrl* list = wxDynamicCast(wxobject, wxDataViewListCtrl);
        if (NULL == list) {
            // very very strange
            return;
        }
        size_t count = GetManager()->GetChildCount(wxobject);
        for (size_t i = 0; i < count; ++i) {
            wxObject* child = GetManager()->GetChild(wxobject, i);
            IObject* childObj = GetManager()->GetIObject(child);
            if (childObj->GetClassName() == _("dataViewListColumn")) {
                if (childObj->GetPropertyAsString(_("type")) == _("Text")) {
                    auto* col = list->AppendTextColumn(
                      childObj->GetPropertyAsString(_("label")),
                      static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
                      childObj->GetPropertyAsInteger(_("width")),
                      static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
                      childObj->GetPropertyAsInteger(_("flags")));
                    if (!childObj->IsPropertyNull(_("ellipsize"))) {
                        col->GetRenderer()->EnableEllipsize(
                          static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
                    }
                } else if (childObj->GetPropertyAsString(_("type")) == _("Toggle")) {
                    auto* col = list->AppendToggleColumn(
                      childObj->GetPropertyAsString(_("label")),
                      static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
                      childObj->GetPropertyAsInteger(_("width")),
                      static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
                      childObj->GetPropertyAsInteger(_("flags")));
                    if (!childObj->IsPropertyNull(_("ellipsize"))) {
                        col->GetRenderer()->EnableEllipsize(
                          static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
                    }
                } else if (childObj->GetPropertyAsString(_("type")) == _("Progress")) {
                    auto* col = list->AppendProgressColumn(
                      childObj->GetPropertyAsString(_("label")),
                      static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
                      childObj->GetPropertyAsInteger(_("width")),
                      static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
                      childObj->GetPropertyAsInteger(_("flags")));
                    if (!childObj->IsPropertyNull(_("ellipsize"))) {
                        col->GetRenderer()->EnableEllipsize(
                          static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
                    }
                } else if (childObj->GetPropertyAsString(_("type")) == _("IconText")) {
                    auto* col = list->AppendIconTextColumn(
                      childObj->GetPropertyAsString(_("label")),
                      static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
                      childObj->GetPropertyAsInteger(_("width")),
                      static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
                      childObj->GetPropertyAsInteger(_("flags")));
                    if (!childObj->IsPropertyNull(_("ellipsize"))) {
                        col->GetRenderer()->EnableEllipsize(
                          static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
                    }
                }
            }
        }
    }
};

class DataViewListColumn : public ComponentBase
{
};

class DataViewColumn : public ComponentBase
{
};

class wxcoreTreeListCtrlComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxTreeListCtrl* treeListCtrl = new wxTreeListCtrl(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        return treeListCtrl;
    }

    void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override
    {
        // initialize tree
        wxTreeListCtrl* treeListCtrl = wxDynamicCast(wxobject, wxTreeListCtrl);
        int colCount = treeListCtrl->GetColumnCount();

        // Check for columns
        if (0 == colCount) {
            return;
        }

        wxTreeListItem root = treeListCtrl->GetRootItem();

        wxTreeListItem treeListParent;
        wxTreeListItem treeListItem;
        int n = 0;

        // Build tree.
        treeListItem = treeListCtrl->AppendItem(root, wxString::Format(_("Item #%d"), ++n));
        FillItem(treeListCtrl, treeListItem, colCount, n);

        treeListParent = treeListItem;
        for (int i = 0; i < 5; ++i) {
            treeListItem = treeListCtrl->AppendItem(treeListParent, wxString::Format(_("Item #%d"), ++n));
            FillItem(treeListCtrl, treeListItem, colCount, n);
        }
        treeListCtrl->Expand(treeListParent);

        treeListParent = treeListItem;
        for (int i = 0; i < 5; ++i) {
            treeListItem = treeListCtrl->AppendItem(treeListParent, wxString::Format(_("Item #%d"), ++n));
            FillItem(treeListCtrl, treeListItem, colCount, n);
        }
        treeListCtrl->Expand(treeListParent);
    }

    void FillItem(wxTreeListCtrl* treeListCtrl, wxTreeListItem itemId, int colCount, int row)
    {
        for (int i = 0; i < colCount; ++i) {
            treeListCtrl->SetItemText(itemId, i, wxString::Format(_("Item #%d, column #%d"), row, i));
        }
    }
};

class wxcoreTreeListCtrlColumnComponent : public ComponentBase
{
public:
    void OnCreated(wxObject* wxobject, wxWindow* wxparent) override
    {
        IObject* obj = GetManager()->GetIObject(wxobject);
        wxTreeListCtrl* treeList = wxDynamicCast(wxparent, wxTreeListCtrl);

        if (!(obj && treeList)) {
            wxLogError(
              _("wxcoreTreeListCtrlColumnComponent is missing its wxFormBuilder object(%i) or its parent(%i)"), obj,
              treeList);
            return;
        }

        treeList->AppendColumn(
          obj->GetPropertyAsString(_("name")), obj->GetPropertyAsInteger(_("width")),
          static_cast<wxAlignment>(obj->GetPropertyAsInteger(_("alignment"))), obj->GetPropertyAsInteger(_("flag")));
    }

    void OnSelected(wxObject*) override {}
};

class RibbonBarComponent : public ComponentBase
{
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxRibbonBar* rb = new wxRibbonBar(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        if (obj->GetPropertyAsString(_("theme")) == _("Default"))
            rb->SetArtProvider(new wxRibbonDefaultArtProvider);
        else if (obj->GetPropertyAsString(_("theme")) == _("Generic"))
            rb->SetArtProvider(new wxRibbonAUIArtProvider);
        else if (obj->GetPropertyAsString(_("theme")) == _("MSW"))
            rb->SetArtProvider(new wxRibbonMSWArtProvider);

        rb->PushEventHandler(new ComponentEvtHandler(rb, GetManager()));

        return rb;
    }

    void Cleanup(wxObject* obj) override
    {
        auto* window = wxDynamicCast(obj, wxRibbonBar);
        if (window) {
            window->PopEventHandler(true);
        }
    }

    void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override
    {
        wxRibbonBar* rb = wxDynamicCast(wxobject, wxRibbonBar);
        if (NULL == rb) {
            // very very strange
            return;
        }

        rb->Realize();
    }
};

class RibbonPageComponent : public ComponentBase
{
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxRibbonPage* rbpage = new wxRibbonPage(
          (wxRibbonBar*)parent, wxID_ANY, obj->GetPropertyAsString(_("label")), obj->GetPropertyAsBitmap(_("bitmap")),
          0);

        if (obj->GetPropertyAsInteger(_("select")) != 0) {
            ((wxRibbonBar*)parent)->SetActivePage(rbpage);
        }

        // rbpage->PushEventHandler( new ComponentEvtHandler( rbpage, GetManager() ) );

        return rbpage;
    }

    /*
    void Cleanup(wxObject* obj) override
    {
            auto* window = wxDynamicCast(obj, wxRibbonPage);
            if (window)
            {
                    window->PopEventHandler(true);
            }
    }
    */
};

class RibbonPanelComponent : public ComponentBase
{
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxRibbonPanel* rbp = new wxRibbonPanel(
          (wxRibbonPage*)parent, wxID_ANY, obj->GetPropertyAsString(_("label")), obj->GetPropertyAsBitmap(_("bitmap")),
          obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        // rbp->PushEventHandler( new ComponentEvtHandler( rbp, GetManager() ) );

        return rbp;
    }

    /*
    void Cleanup(wxObject* obj) override
    {
            auto* window = wxDynamicCast(obj, wxRibbonPanel);
            if (window)
            {
                    window->PopEventHandler(true);
            }
    }
    */
};

class RibbonButtonBarComponent : public ComponentBase
{
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxRibbonButtonBar* rbb = new wxRibbonButtonBar(
          (wxRibbonPanel*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")), 0);

        // rbb->PushEventHandler( new ComponentEvtHandler( rbb, GetManager() ) );

        return rbb;
    }

    /*
    void Cleanup(wxObject* obj) override
    {
            auto* window = wxDynamicCast(obj, wxRibbonButtonBar);
            if (window)
            {
                    window->PopEventHandler(true);
            }
    }
    */

    void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override
    {
        wxRibbonButtonBar* rb = wxDynamicCast(wxobject, wxRibbonButtonBar);
        if (NULL == rb) {
            // very very strange
            return;
        }

        size_t count = GetManager()->GetChildCount(wxobject);
        for (size_t i = 0; i < count; ++i) {
            wxObject* child = GetManager()->GetChild(wxobject, i);
            IObject* childObj = GetManager()->GetIObject(child);
            if (childObj->GetClassName() == wxT("ribbonButton")) {
                rb->AddButton(
                  wxID_ANY, childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsBitmap(_("bitmap")),
                  childObj->GetPropertyAsString(_("help")));
            } else if (childObj->GetClassName() == wxT("ribbonDropdownButton")) {
                rb->AddDropdownButton(
                  wxID_ANY, childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsBitmap(_("bitmap")),
                  childObj->GetPropertyAsString(_("help")));
            } else if (childObj->GetClassName() == wxT("ribbonHybridButton")) {
                rb->AddHybridButton(
                  wxID_ANY, childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsBitmap(_("bitmap")),
                  childObj->GetPropertyAsString(_("help")));
            } else if (childObj->GetClassName() == wxT("ribbonToggleButton")) {
                rb->AddToggleButton(
                  wxID_ANY, childObj->GetPropertyAsString(_("label")), childObj->GetPropertyAsBitmap(_("bitmap")),
                  childObj->GetPropertyAsString(_("help")));
            }
        }
    }
};

class RibbonButtonComponent : public ComponentBase
{
};
class RibbonDropdownButtonComponent : public ComponentBase
{
};
class RibbonHybridButtonComponent : public ComponentBase
{
};
class RibbonToggleButtonComponent : public ComponentBase
{
};

class RibbonToolBarComponent : public ComponentBase
{
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxRibbonToolBar* rbb = new wxRibbonToolBar(
          (wxRibbonPanel*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")), 0);

        // rbb->PushEventHandler( new ComponentEvtHandler( rbb, GetManager() ) );

        return rbb;
    }

    /*
    void Cleanup(wxObject* obj) override
    {
            auto* window = wxDynamicCast(obj, wxRibbonToolBar);
            if (window)
            {
                    window->PopEventHandler(true);
            }
    }
    */

    void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override
    {
        wxRibbonToolBar* rb = wxDynamicCast(wxobject, wxRibbonToolBar);
        if (NULL == rb) {
            // very very strange
            return;
        }

        size_t count = GetManager()->GetChildCount(wxobject);
        for (size_t i = 0; i < count; ++i) {
            wxObject* child = GetManager()->GetChild(wxobject, i);
            IObject* childObj = GetManager()->GetIObject(child);
            if (wxT("ribbonTool") == childObj->GetClassName()) {
                rb->AddTool(
                  wxID_ANY, childObj->GetPropertyAsBitmap(_("bitmap")), childObj->GetPropertyAsString(_("help")));
            } else if (wxT("ribbonDropdownTool") == childObj->GetClassName()) {
                rb->AddDropdownTool(
                  wxID_ANY, childObj->GetPropertyAsBitmap(_("bitmap")), childObj->GetPropertyAsString(_("help")));
            } else if (wxT("ribbonHybridTool") == childObj->GetClassName()) {
                rb->AddHybridTool(
                  wxID_ANY, childObj->GetPropertyAsBitmap(_("bitmap")), childObj->GetPropertyAsString(_("help")));
            } else if (wxT("ribbonToggleTool") == childObj->GetClassName()) {
                rb->AddToggleTool(
                  wxID_ANY, childObj->GetPropertyAsBitmap(_("bitmap")), childObj->GetPropertyAsString(_("help")));
            }
        }
    }
};

class RibbonToolComponent : public ComponentBase
{
};

class RibbonDropdownToolComponent : public ComponentBase
{
};

class RibbonHybridToolComponent : public ComponentBase
{
};

class RibbonToggleToolComponent : public ComponentBase
{
};

class RibbonGalleryComponent : public ComponentBase
{
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxRibbonGallery* ribbonGallery = new wxRibbonGallery(
          (wxRibbonPanel*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")), 0);

        // ribbonGallery->PushEventHandler( new ComponentEvtHandler( ribbonGallery, GetManager() ) );

        return ribbonGallery;
    }

    /*
    void Cleanup(wxObject* obj) override
    {
            auto* window = wxDynamicCast(obj, wxRibbonGallery);
            if (window)
            {
                    window->PopEventHandler(true);
            }
    }
    */

    void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override
    {
        wxRibbonGallery* rg = wxDynamicCast(wxobject, wxRibbonGallery);
        if (NULL == rg) {
            // very very strange
            return;
        }

        size_t count = GetManager()->GetChildCount(wxobject);
        for (size_t i = 0; i < count; ++i) {
            wxObject* child = GetManager()->GetChild(wxobject, i);
            IObject* childObj = GetManager()->GetIObject(child);
            if (wxT("ribbonGalleryItem") == childObj->GetClassName()) {
                rg->Append(childObj->GetPropertyAsBitmap(_("bitmap")), wxID_ANY);
            }
        }
    }
};

class RibbonGalleryItemComponent : public ComponentBase
{
};

#if !wxCHECK_VERSION(3, 3, 0)
    namespace
    {
        class wxVListBoxXmlHandler : public wxXmlResourceHandler
        {
        public:
            wxVListBoxXmlHandler();
            wxObject *DoCreateResource() override;
            bool CanHandle(wxXmlNode *node) override;
        };
    }

    namespace
    {
        const char wxXRCPreviewVListBoxNameStr[] = "wxXRCPreviewVListBox";

        /*
            GUI editors, e.g., wxFormBuilder, typically allow users to lay out
            instances of controls.  However, wxVListBox is an abstract class, so a GUI
            editor can only create instances of a subclass of wxVListBox.  Rather than
            require every GUI editor to repeat the work of subclassing wxVListBox for
            GUI editing, and because the user's intended subclass will not exist in GUI
            editors, provide a class that GUI editors can use.  Also, the
            wxVListBoxXmlHandler can create instances of this class when in
            wxXRC_NO_SUBCLASSING mode;
         */
        class wxXRCPreviewVListBox : public wxVListBox
        {
        public:
            // default constructor, you must call Create() later
            wxXRCPreviewVListBox() = default;

            // normal constructor which calls Create() internally
            wxXRCPreviewVListBox(wxWindow *parent,
                                    wxWindowID id = wxID_ANY,
                                    const wxPoint& pos = wxDefaultPosition,
                                    const wxSize& size = wxDefaultSize,
                                    long style = 0,
                                    const wxString& name = wxString::FromAscii(wxXRCPreviewVListBoxNameStr))
            {
                (void)Create(parent, id, pos, size, style, name);
            }

            // really creates the control and sets the initial number of items in it
            // (which may be changed later with SetItemCount())
            //
            // the only special style which may be specified here is wxLB_MULTIPLE
            //
            // returns true on success or false if the control couldn't be created
            bool Create(wxWindow *parent,
                        wxWindowID id = wxID_ANY,
                        const wxPoint& pos = wxDefaultPosition,
                        const wxSize& size = wxDefaultSize,
                        long style = 0,
                        const wxString& name = wxString::FromAscii(wxXRCPreviewVListBoxNameStr));

        protected:
            // avoid defaulting to tiny window
            wxSize DoGetBestClientSize() const override;

            // the derived class must implement this function to actually draw the item
            // with the given index on the provided DC
            void OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const override;

            // the derived class must implement this method to return the height of the
            // specified item
            wxCoord OnMeasureItem(size_t n) const override;

        private:
            wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxXRCPreviewVListBox);

            wxString GetItem(size_t n) const;
        };

        wxIMPLEMENT_DYNAMIC_CLASS(wxXRCPreviewVListBox, wxVListBox);

        bool wxXRCPreviewVListBox::Create(wxWindow *parent,
                    wxWindowID id /*= wxID_ANY*/,
                    const wxPoint& pos /*= wxDefaultPosition*/,
                    const wxSize& size /*= wxDefaultSize*/,
                    long style /*= 0*/,
                    const wxString& name /*= wxASCII_STR(wxVListBoxNameStr)*/)
        {
            bool retval = wxVListBox::Create(parent, id, pos, size, style, name);
            if (retval)
            {
                SetItemCount(std::numeric_limits<int>::max());
            }
            return retval;
        }

        // avoid defaulting to tiny window
        wxSize wxXRCPreviewVListBox::DoGetBestClientSize() const
        {
            // safe to const_cast since we're just using GetTextExtent()/GetMetric()
            wxXRCPreviewVListBox* nonConstThis = const_cast<wxXRCPreviewVListBox*>(this);
            wxClientDC dc(nonConstThis);
            wxSize item99Size = dc.GetTextExtent(GetItem(99));
            return wxSize(item99Size.x + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X, nonConstThis),
                            5 * item99Size.y);
        }

        void wxXRCPreviewVListBox::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const
        {
            dc.DrawText(GetItem(n), rect.GetLeftTop());
        }

        wxCoord wxXRCPreviewVListBox::OnMeasureItem(size_t n) const
        {
            // safe to const_cast since we're just using GetTextExtent()
            wxWindowDC dc(const_cast<wxXRCPreviewVListBox*>(this));
            return dc.GetTextExtent(GetItem(n)).y;
        }

        wxString wxXRCPreviewVListBox::GetItem(size_t n) const
        {
            return wxString::Format("Item %zu", n);
        }

        wxVListBoxXmlHandler::wxVListBoxXmlHandler() : wxXmlResourceHandler()
        {
            // panel styles
            XRC_ADD_STYLE(wxTAB_TRAVERSAL);

            // listbox styles
            XRC_ADD_STYLE(wxLB_MULTIPLE);

            AddWindowStyles();
        }

        wxObject * wxVListBoxXmlHandler::DoCreateResource()
        {
            // see comment for wxXRCPreviewVListBox

            /* Create() isn't virtual, but the preview class has its
                own implementation, so we need to use the static type
                of the pointer to get the correct version */
            wxXRCPreviewVListBox* preview = nullptr;
            if (!m_instance &&
                m_resource->GetFlags() & wxXRC_NO_SUBCLASSING)
            {
                preview = new wxXRCPreviewVListBox;
                m_instance = preview;
            }

            /* non-standard because wxVListBox is an abstract
                class, so "subclass" must be used */
            wxCHECK_MSG(m_instance,
                        nullptr,
                        "wxVListBox requires \"subclass\" attribute");
            wxVListBox* const vlistbox = wxStaticCast(m_instance, wxVListBox);
            if (GetBool(wxT("hidden"), 0) == 1)
                vlistbox->Hide();

            if (!preview)
            {
                vlistbox->Create(m_parentAsWindow,
                              GetID(),
                              GetPosition(), GetSize(),
                              GetStyle(wxT("style"), wxTAB_TRAVERSAL),
                              GetName());
            }
            else
            {
                preview->Create(m_parentAsWindow,
                              GetID(),
                              GetPosition(), GetSize(),
                              GetStyle(wxT("style"), wxTAB_TRAVERSAL),
                              GetName());
            }

            SetupWindow(vlistbox);
            CreateChildren(vlistbox);

            return vlistbox;
        }

        bool wxVListBoxXmlHandler::CanHandle(wxXmlNode *node)
        {
            return IsOfClass(node, wxT("wxVListBox"));
        }
    }
#endif

class VListBoxComponent : public ComponentBase
{
public:
    wxObject* Create(IObject* obj, wxObject* parent) override
    {
        wxVListBox* listbox = new wxXRCPreviewVListBox(
          (wxWindow*)parent, wxID_ANY, obj->GetPropertyAsPoint(_("pos")), obj->GetPropertyAsSize(_("size")),
          obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

        return listbox;
    }

    tinyxml2::XMLElement* ExportToXrc(tinyxml2::XMLElement* xrc, const IObject* obj) override
    {
        ObjectToXrcFilter filter(xrc, GetLibrary(), obj);
        filter.AddWindowProperties();
        return xrc;
    }

    tinyxml2::XMLElement* ImportFromXrc(tinyxml2::XMLElement* xfb, const tinyxml2::XMLElement* xrc) override
    {
        XrcToXfbFilter filter(xfb, GetLibrary(), xrc);
        filter.AddWindowProperties();
        return xfb;
    }
};

///////////////////////////////////////////////////////////////////////////////

BEGIN_LIBRARY()

#if !wxCHECK_VERSION(3, 3, 0)
    wxXmlResource::Get()->AddHandler(new wxVListBoxXmlHandler);
#endif

WINDOW_COMPONENT("wxCalendarCtrl", CalendarCtrlComponent)
WINDOW_COMPONENT("wxDatePickerCtrl", DatePickerCtrlComponent)
WINDOW_COMPONENT("wxTimePickerCtrl", TimePickerCtrlComponent)
WINDOW_COMPONENT("wxHtmlWindow", HtmlWindowComponent)
WINDOW_COMPONENT("wxToggleButton", ToggleButtonComponent)
WINDOW_COMPONENT("wxBitmapToggleButton", BitmapToggleButtonComponent)
WINDOW_COMPONENT("wxTreeCtrl", TreeCtrlComponent)
WINDOW_COMPONENT("wxGrid", GridComponent)
WINDOW_COMPONENT("wxScrollBar", ScrollBarComponent)
WINDOW_COMPONENT("wxSpinCtrl", SpinCtrlComponent)
WINDOW_COMPONENT("wxSpinButton", SpinButtonComponent)
WINDOW_COMPONENT("CustomControl", CustomControlComponent)
ABSTRACT_COMPONENT("CustomCode", CustomCodeComponent)
WINDOW_COMPONENT("wxDataViewCtrl", DataViewCtrl)
WINDOW_COMPONENT("wxDataViewTreeCtrl", DataViewTreeCtrl)
WINDOW_COMPONENT("wxDataViewListCtrl", DataViewListCtrl)
ABSTRACT_COMPONENT("dataViewListColumn", DataViewListColumn)
ABSTRACT_COMPONENT("dataViewColumn", DataViewColumn)
WINDOW_COMPONENT("wxRibbonBar", RibbonBarComponent)
WINDOW_COMPONENT("wxRibbonPage", RibbonPageComponent)
WINDOW_COMPONENT("wxRibbonPanel", RibbonPanelComponent)
WINDOW_COMPONENT("wxRibbonButtonBar", RibbonButtonBarComponent)
WINDOW_COMPONENT("wxRibbonToolBar", RibbonToolBarComponent)
WINDOW_COMPONENT("wxRibbonGallery", RibbonGalleryComponent)
ABSTRACT_COMPONENT("ribbonButton", RibbonButtonComponent)
ABSTRACT_COMPONENT("ribbonDropdownButton", RibbonDropdownButtonComponent)
ABSTRACT_COMPONENT("ribbonHybridButton", RibbonHybridButtonComponent)
ABSTRACT_COMPONENT("ribbonToggleButton", RibbonToggleButtonComponent)
ABSTRACT_COMPONENT("ribbonTool", RibbonToolComponent)
ABSTRACT_COMPONENT("ribbonDropdownTool", RibbonDropdownToolComponent)
ABSTRACT_COMPONENT("ribbonHybridTool", RibbonHybridToolComponent)
ABSTRACT_COMPONENT("ribbonToggleTool", RibbonToggleToolComponent)
ABSTRACT_COMPONENT("ribbonGalleryItem", RibbonGalleryItemComponent)

// wxCheckListBox
WINDOW_COMPONENT("wxCheckListBox", CheckListBoxComponent)

#ifdef USE_MEDIACTRL
WINDOW_COMPONENT("wxMediaCtrl", MediaCtrlComponent)
#endif

// wxRichTextCtrl
WINDOW_COMPONENT("wxRichTextCtrl", RichTextCtrlComponent)
MACRO(wxTE_PROCESS_ENTER);
MACRO(wxTE_PROCESS_TAB);
MACRO(wxTE_READONLY);
MACRO(wxTE_AUTO_URL);

// wxColourPickerCtrl
WINDOW_COMPONENT("wxColourPickerCtrl", ColourPickerComponent)
MACRO(wxCLRP_DEFAULT_STYLE)
MACRO(wxCLRP_USE_TEXTCTRL)
MACRO(wxCLRP_SHOW_LABEL)

// wxFontPickerCtrl
WINDOW_COMPONENT("wxFontPickerCtrl", FontPickerComponent)
MACRO(wxFNTP_DEFAULT_STYLE)
MACRO(wxFNTP_USE_TEXTCTRL)
MACRO(wxFNTP_FONTDESC_AS_LABEL)
MACRO(wxFNTP_USEFONT_FOR_LABEL)

// wxFilePickerCtrl
WINDOW_COMPONENT("wxFilePickerCtrl", FilePickerComponent)
MACRO(wxFLP_DEFAULT_STYLE)
MACRO(wxFLP_USE_TEXTCTRL)
MACRO(wxFLP_OPEN)
MACRO(wxFLP_SAVE)
MACRO(wxFLP_OVERWRITE_PROMPT)
MACRO(wxFLP_FILE_MUST_EXIST)
MACRO(wxFLP_CHANGE_DIR)
MACRO(wxFLP_SMALL)

// wxDirPickerCtrl
WINDOW_COMPONENT("wxDirPickerCtrl", DirPickerComponent)
MACRO(wxDIRP_DEFAULT_STYLE)
MACRO(wxDIRP_USE_TEXTCTRL)
MACRO(wxDIRP_DIR_MUST_EXIST)
MACRO(wxDIRP_CHANGE_DIR)
MACRO(wxDIRP_SMALL)

// wxHyperlinkCtrl
WINDOW_COMPONENT("wxHyperlinkCtrl", HyperlinkComponent)
MACRO(wxHL_ALIGN_LEFT)
MACRO(wxHL_ALIGN_RIGHT)
MACRO(wxHL_ALIGN_CENTRE)
MACRO(wxHL_CONTEXTMENU)
MACRO(wxHL_DEFAULT_STYLE)

// wxSearchCtrl
WINDOW_COMPONENT("wxSearchCtrl", SearchCtrlComponent)
MACRO(wxTE_PROCESS_ENTER);
MACRO(wxTE_PROCESS_TAB);
MACRO(wxTE_NOHIDESEL);
MACRO(wxTE_LEFT);
MACRO(wxTE_CENTER);
MACRO(wxTE_RIGHT);
MACRO(wxTE_CAPITALIZE);

WINDOW_COMPONENT("wxSpinCtrlDouble", SpinCtrlDoubleComponent)

// wxCalendarCtrl
MACRO(wxCAL_SUNDAY_FIRST)
MACRO(wxCAL_MONDAY_FIRST)
MACRO(wxCAL_SHOW_HOLIDAYS)
MACRO(wxCAL_NO_YEAR_CHANGE)
MACRO(wxCAL_NO_MONTH_CHANGE)
MACRO(wxCAL_SHOW_SURROUNDING_WEEKS)
MACRO(wxCAL_SEQUENTIAL_MONTH_SELECTION)
MACRO(wxCAL_SHOW_WEEK_NUMBERS)

// wxDatePickerCtrl
MACRO(wxDP_SPIN)
MACRO(wxDP_DROPDOWN)
MACRO(wxDP_SHOWCENTURY)
MACRO(wxDP_ALLOWNONE)
MACRO(wxDP_DEFAULT)

// wxTimePickerCtrl
MACRO(wxTP_DEFAULT)

// wxHtmlWindow
MACRO(wxHW_SCROLLBAR_NEVER)
MACRO(wxHW_SCROLLBAR_AUTO)
MACRO(wxHW_NO_SELECTION)

// wxTreeCtrl
MACRO(wxTR_EDIT_LABELS)
MACRO(wxTR_NO_BUTTONS)
MACRO(wxTR_HAS_BUTTONS)
MACRO(wxTR_TWIST_BUTTONS)
MACRO(wxTR_NO_LINES)
MACRO(wxTR_FULL_ROW_HIGHLIGHT)
MACRO(wxTR_LINES_AT_ROOT)
MACRO(wxTR_HIDE_ROOT)
MACRO(wxTR_ROW_LINES)
MACRO(wxTR_HAS_VARIABLE_ROW_HEIGHT)
MACRO(wxTR_SINGLE)
MACRO(wxTR_MULTIPLE)
MACRO(wxTR_DEFAULT_STYLE)

// wxGrid
MACRO(wxALIGN_LEFT)
MACRO(wxALIGN_CENTER)
MACRO(wxALIGN_RIGHT)
MACRO(wxALIGN_TOP)
MACRO(wxALIGN_BOTTOM)
MACRO(wxGRID_AUTOSIZE)

// wxScrollBar
MACRO(wxSB_HORIZONTAL)
MACRO(wxSB_VERTICAL)

// wxSpinCtrl and wxSpinButton
MACRO(wxSP_ARROW_KEYS)
MACRO(wxSP_WRAP)
MACRO(wxSP_HORIZONTAL)
MACRO(wxSP_VERTICAL)

// wxGenericDirCtrl
WINDOW_COMPONENT("wxGenericDirCtrl", GenericDirCtrlComponent)
MACRO(wxDIRCTRL_DIR_ONLY)
MACRO(wxDIRCTRL_3D_INTERNAL)
MACRO(wxDIRCTRL_SELECT_FIRST)
MACRO(wxDIRCTRL_EDIT_LABELS)
MACRO(wxDIRCTRL_MULTIPLE)

// wxTimer
ABSTRACT_COMPONENT("wxTimer", TimerComponent)

// wxPropertyGrid
WINDOW_COMPONENT("wxPropertyGrid", PropertyGridComponent)
ABSTRACT_COMPONENT("propGridItem", PropertyGridItemComponent)
MACRO(wxPG_DEFAULT_STYLE)
MACRO(wxPG_AUTO_SORT)
MACRO(wxPG_HIDE_CATEGORIES)
MACRO(wxPG_ALPHABETIC_MODE)
MACRO(wxPG_BOLD_MODIFIED)
MACRO(wxPG_SPLITTER_AUTO_CENTER)
MACRO(wxPG_TOOLTIPS)
MACRO(wxPG_HIDE_MARGIN)
MACRO(wxPG_STATIC_SPLITTER)
MACRO(wxPG_STATIC_LAYOUT)
MACRO(wxPG_LIMITED_EDITING)
MACRO(wxPG_EX_INIT_NOCAT)
MACRO(wxPG_EX_HELP_AS_TOOLTIPS)
MACRO(wxPG_EX_NATIVE_DOUBLE_BUFFERING)
MACRO(wxPG_EX_AUTO_UNSPECIFIED_VALUES)
MACRO(wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES)
MACRO(wxPG_EX_MULTIPLE_SELECTION)
MACRO(wxPG_EX_ENABLE_TLP_TRACKING)

// wxPropertyGridManager
WINDOW_COMPONENT("wxPropertyGridManager", PropertyGridManagerComponent)
ABSTRACT_COMPONENT("propGridPage", PropertyGridPageComponent)
MACRO(wxPG_EX_NO_FLAT_TOOLBAR)
MACRO(wxPG_EX_MODE_BUTTONS)
MACRO(wxPG_EX_HIDE_PAGE_BUTTONS)
MACRO(wxPG_EX_NO_TOOLBAR_DIVIDER)
MACRO(wxPG_EX_TOOLBAR_SEPARATOR)
MACRO(wxPGMAN_DEFAULT_STYLE)
MACRO(wxPG_DESCRIPTION)
MACRO(wxPG_TOOLBAR)
MACRO(wxPG_NO_INTERNAL_BORDER)

// wxStyledTextCtrl
WINDOW_COMPONENT("wxStyledTextCtrl", StyledTextComponent)

// wxDataViewCtrl
MACRO(wxDV_SINGLE)
MACRO(wxDV_MULTIPLE)
MACRO(wxDV_ROW_LINES)
MACRO(wxDV_HORIZ_RULES)
MACRO(wxDV_VERT_RULES)
MACRO(wxDV_VARIABLE_LINE_HEIGHT)
MACRO(wxDV_NO_HEADER)

MACRO(wxDATAVIEW_CELL_INERT)
MACRO(wxDATAVIEW_CELL_ACTIVATABLE)
MACRO(wxDATAVIEW_CELL_EDITABLE)

MACRO(wxDATAVIEW_COL_RESIZABLE)
MACRO(wxDATAVIEW_COL_SORTABLE)
MACRO(wxDATAVIEW_COL_REORDERABLE)
MACRO(wxDATAVIEW_COL_HIDDEN)

MACRO(wxELLIPSIZE_NONE)
MACRO(wxELLIPSIZE_START)
MACRO(wxELLIPSIZE_MIDDLE)
MACRO(wxELLIPSIZE_END)

MACRO(wxALIGN_LEFT)
MACRO(wxALIGN_TOP)
MACRO(wxALIGN_RIGHT)
MACRO(wxALIGN_BOTTOM)
MACRO(wxALIGN_CENTER)
MACRO(wxALIGN_CENTER_HORIZONTAL)
MACRO(wxALIGN_CENTER_VERTICAL)

// wxRibbonBar
MACRO(wxRIBBON_BAR_DEFAULT_STYLE)
MACRO(wxRIBBON_BAR_FOLDBAR_STYLE)
MACRO(wxRIBBON_BAR_SHOW_PAGE_LABELS)
MACRO(wxRIBBON_BAR_SHOW_PAGE_ICONS)
MACRO(wxRIBBON_BAR_FLOW_HORIZONTAL)
MACRO(wxRIBBON_BAR_FLOW_VERTICAL)
MACRO(wxRIBBON_BAR_SHOW_PANEL_EXT_BUTTONS)
MACRO(wxRIBBON_BAR_SHOW_PANEL_MINIMISE_BUTTONS)
MACRO(wxRIBBON_BAR_SHOW_TOGGLE_BUTTON)
MACRO(wxRIBBON_BAR_SHOW_HELP_BUTTON)

// wxRibbonPanel
MACRO(wxRIBBON_PANEL_DEFAULT_STYLE)
MACRO(wxRIBBON_PANEL_NO_AUTO_MINIMISE)
MACRO(wxRIBBON_PANEL_EXT_BUTTON)
MACRO(wxRIBBON_PANEL_MINIMISE_BUTTON)
MACRO(wxRIBBON_PANEL_STRETCH)
MACRO(wxRIBBON_PANEL_FLEXIBLE)

// wxTreeListCtrl
WINDOW_COMPONENT("wxTreeListCtrl", wxcoreTreeListCtrlComponent)
MACRO(wxTL_SINGLE)
MACRO(wxTL_MULTIPLE)
MACRO(wxTL_CHECKBOX)
MACRO(wxTL_3STATE)
MACRO(wxTL_USER_3STATE)
MACRO(wxTR_DEFAULT_STYLE)

// wxVListBox
WINDOW_COMPONENT("wxVListBox", VListBoxComponent)
MACRO(wxLB_MULTIPLE)

ABSTRACT_COMPONENT("wxTreeListCtrlColumn", wxcoreTreeListCtrlColumnComponent)
MACRO(wxCOL_RESIZABLE)
MACRO(wxCOL_SORTABLE)
MACRO(wxCOL_REORDERABLE)
MACRO(wxCOL_HIDDEN)

END_LIBRARY()
